﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "ActionDrawWall.h"
#include "IUiDocument.h"
#include "IDocument.h"
#include "IUiView.h"
#include "IPlane.h"
#include "IUserTransaction.h"
#include "../UIPlatform/CommandIds.h"
#include "CommandIds.h"
#include "IElementModelShape.h"
#include "IGraphicsElementShape.h"
#include "ITemporaryDimensionContext.h"
#include "IPickPointAction.h"
#include "Vector3dUtils.h"
#include "UiCommonDialog.h"
#include "Wall\Wall.h"
#include "ISnap.h"
#include "IGraphicsNodeReference.h"
#include "ISnapContext.h"
#include "IModelView.h"
#include "ITemporaryDimensionManager.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "IGraphicsStyleManager.h"
#include "IGraphicsBRepBody.h"
#include "ICategory.h"
#include "GraphicsNodeUtils.h"
#include "ICategoryLibrary.h"
#include "IRegenerator.h"
#include "ISnapSettings.h"
#include "ICommandManager.h"
#include "IPickPointActionConfig.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h" 
using namespace Sample;
using namespace gcmp;

bool GetCustomMousePath(std::wstring & cursorPath)
{
    cursorPath = L":/images/Cursor/cross.png";
    return true;
}

namespace Sample
{
    class WallPickConfigure : public gcmp::IPickPointActionConfig
    {
        DEFINE_CAST_DERIVED(WallPickConfigure, gcmp::IPickPointActionConfig);
    public:
        WallPickConfigure(ActionDrawWall* pAction) :m_ParentAction(pAction) {};
        virtual ~WallPickConfigure() {};

        // 用户配置自定义的正交模式
        virtual bool ConfigSnapSettings(ISnapSettings* snapSetting) override
        {
            if (snapSetting)
            {
                snapSetting->SetIsForceHorizontalOrVertical(m_ParentAction->GetCtrlKeyPressed());
            }
            return false;
        };

    private:
        ActionDrawWall* m_ParentAction;
    };
}


ActionDrawWall::ActionDrawWall()
    : m_drawStatus(eWait)
    , m_isUserCancelled(false)
    , m_opSnapStart(nullptr)
    , m_opSnapEnd(nullptr)
{
    ISnapSettings* opSetting = ISnapSettings::GetGlobalSnapSettings();
    m_opOldSetting = opSetting->Clone();
}

ActionDrawWall::~ActionDrawWall()
{
    ISnapSettings* opSetting = ISnapSettings::GetGlobalSnapSettings();
    if (m_opOldSetting.get())
    {
        opSetting->SetSnapSettings(m_opOldSetting.get());
    }
}

void ActionDrawWall::OnChildActionFinished(IUiView* pCurrentView, const ActionOutput& childActionReturnParam)
{
    if (m_drawStatus == eGetting_StartPoint)
    {
        if (m_isUserCancelled)
        {
            // 如果用户在画第一个点时就选择退出，那么就退出整个画线工具
            CleanupTempGraphicsShape();
            MarkFinishStatus(ActionFinishStatus::Cancelled);
        }
        else
        {
            EnterGettingEndPointState(pCurrentView);
        }
    }
    else if (m_drawStatus == eGetting_EndPoint)
    {
        CleanupTempGraphicsShape();
        m_pickedPoints.clear();
        if (m_isUserCancelled)
        {
            // 如果用户在画第二个点时选择退出，那么先退到画第一个点的状态
            EnterGettingStartPointState(pCurrentView);
            UpdateView();
            return;
        }
        else if (Vector3dUtils::IsEqual(m_ptStart, m_ptEnd))
        {
            UiCommonDialog::ShowMessageBox(GBMP_TR(L"绘制墙体"), GBMP_TR(L"起始点和终止点不能相同"),
                (int)UiCommonDialog::ButtonType::OK);
            EnterGettingEndPointState(pCurrentView);
        }
        else
        {
            ElementId id = OnDrawFinished(pCurrentView, m_ptStart, m_ptEnd);
            if (id.IsValid())
            {
                m_ptStart = m_ptEnd;
                EnterGettingEndPointState(pCurrentView);
            }
            else
            {
                EnterGettingStartPointState(pCurrentView);
            }
        }
    }
    UpdateView();
}

void ActionDrawWall::EnterGettingStartPointState(gcmp::IUiView* pCurrentView)
{
    m_drawStatus = eGetting_StartPoint;
    SetPromptMessage(GBMP_TR(L"请输入起始点"));
    //设置三维点捕捉
    PickPointExchangeData exchangeData(&m_ptStart, &m_isUserCancelled, &m_pickedPoints, &m_opSnapStart, nullptr);
    {
        //仅输入xy值
#if 0
        exchangeData.m_pickPointType = PickPointExchangeData::PickPointType::TwoDimensionPoint;
#endif
    }

    gcmp::OwnerPtr<IPickPointAction> opPickPointAction = IPickPointAction::Create(exchangeData);

    ISnapContext* opContext = opPickPointAction->GetSnapContext();
    ISnapSettings* opSetting = ISnapSettings::GetGlobalSnapSettings();
    opSetting->SetCanSnap3dPoint(true);
    opSetting->SetCanSnap3DAxialDirectionLine(true);
    {
        //延伸捕捉
        opSetting->SetIsRemoteSnapOff(false);
        opSetting->SetCanExtensionSnap(true);
        opSetting->SetCanSnap3DExtension(true);
    }
    opContext->SetSnapSettings(opSetting);
    opPickPointAction->SetSnapContext(opContext);
    {
        //自定义光标
        opPickPointAction->SetCursorType(CursorType::Custom);
        opPickPointAction->SetCursorPathCallBack(GetCustomMousePath);
    }
    {
        //输入坐标可回车确认
        OwnerPtr<IPlane> opWorkPlane;
        if (IModelView* pModelView = pCurrentView->GetModelView())
        {
            opWorkPlane = pModelView->GetWorkPlane();
        }
        opPickPointAction->StartCoordinateInput(TransferOwnership(opWorkPlane));
    }

    StartChildAction(TransferOwnership(opPickPointAction));
}

void ActionDrawWall::EnterGettingEndPointState(gcmp::IUiView* pCurrentView)
{
    m_drawStatus = eGetting_EndPoint;
    m_isUserCancelled = false;
    m_opSnapStart = nullptr;
    SetPromptMessage(GBMP_TR(L"请输入墙体终止点"));
    OwnerPtr<IPickPointActionConfig> opWallPickConfigure = NEW_AS_OWNER_PTR(WallPickConfigure, this);
    //设置三维点捕捉
    PickPointExchangeData exchangeData(&m_ptEnd, &m_isUserCancelled, &m_pickedPoints, &m_opSnapStart, nullptr);
    gcmp::OwnerPtr<IPickPointAction> opPickPointAction = IPickPointAction::Create(exchangeData,
        IPickPointAction::CreateMoveCallback(&ActionDrawWall::OnPointUpdate, this), 
        ActionFinishedMode::LButtonDown, false, TransferOwnership(opWallPickConfigure));

    ISnapContext* opContext = opPickPointAction->GetSnapContext();
    ISnapSettings* opSetting = ISnapSettings::GetGlobalSnapSettings();
    opSetting->SetCanSnap3dPoint(true);
    opSetting->SetCanSnap3DAxialDirectionLine(true);
    {
        //正交必须设置项
        opSetting->SetCanSnapHorizontalVerticalLine(true);
        opSetting->SetIsForceHorizontalOrVertical(true);
        opSetting->SetCanSnapLength(true);
    }
     opSetting->SetCanSnap3DAxialDirectionLine(false);
    {
        //延伸捕捉
        opSetting->SetIsRemoteSnapOff(false);
        opSetting->SetCanExtensionSnap(true);
        opSetting->SetCanSnap3DExtension(true);
    }
    opContext->SetSnapSettings(opSetting);
    opPickPointAction->SetSnapContext(opContext);
    {
        //自定义光标
        opPickPointAction->SetCursorType(CursorType::Custom);
        opPickPointAction->SetCursorPathCallBack(GetCustomMousePath);
    }

    opPickPointAction->SetFirstPoint(m_ptStart);
    StartChildAction(TransferOwnership(opPickPointAction));
}

void ActionDrawWall::OnPointUpdate(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& pickedPt, const gcmp::Vector3d& mousePos)
{
    if (Vector3dUtils::IsEqual(m_ptStart, pickedPt))
        return;
    CleanupTempGraphicsShape();
    OwnerPtr<IGraphicsElementShape> opGraphicsElementShape = OnWallUpdate(pCurrentView, m_ptStart, pickedPt);

    OwnerPtr<ITemporaryDimensionContext> opTemporaryDimensionContext =
        ITemporaryDimensionContext::CreateLinearContext(m_ptStart, pickedPt, true,
            pCurrentView->GetModelView()->GetViewType() == BuiltInViewType::TwoDimensional,
            Coordinate3d(Coordinate3d().GetOrigin(), Coordinate3d().GetY(), -Coordinate3d().GetX()));
    opTemporaryDimensionContext->SetValidRangeOfAngle(Intervald::Create(0.0, 360.0));
    opGraphicsElementShape->AddChild(TransferOwnership(ITemporaryDimensionManager::Get()->
        GenerateTemporaryDimensionGraphics(opTemporaryDimensionContext.get())));

    IUiDocument* pUiDoc = pCurrentView->GetUiDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pUiDoc, L"pUiDoc为空", L"GDMP", L"2023-09-30");
    IDocument* pDoc = pUiDoc->GetDbDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"无效的文档", L"GDMP", L"2023-09-30");

    DrawTempGraphicsElementShape(TransferOwnership(opGraphicsElementShape));
    pCurrentView->GetUiDocument()->UpdateView();
}

void ActionDrawWall::InitAction(gcmp::IUiView* pCurrentView)
{
    EnterGettingStartPointState(pCurrentView);
}

OwnerPtr<IGraphicsElementShape> ActionDrawWall::OnWallUpdate(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& startPt, const gcmp::Vector3d& endPt)
{
    IDocument *pDocument = pCurrentView->GetUiDocument()->GetDbDocument();
    OwnerPtr<IUserTransaction> opUserTransaction =
        IUserTransaction::Create(pDocument, GBMP_TR(L"绘制墙体"));
    Wall* pWall = Wall::Create(pDocument, startPt, endPt, ElementCreationOptions::Transient);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pWall, L"创建墙体失败", L"GDMP", L"2023-09-30");
    pDocument->GetRegenerator()->RegenerateElement(pWall->GetOwnerElementId());
    IElement* pElement = pWall->GetOwnerElement();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElement, L"pElement不能为空", L"GDMP", L"2023-09-30");
    OwnerPtr<IGraphicsElementShape> opGraphicsElementShape = pElement->GetElementModelShape()->TransferGraphicsElementShape();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opGraphicsElementShape, L"opGraphicsElementShape不能为空", L"GDMP", L"2023-09-30");
    pDocument->DeleteElement(pElement->GetElementId());
    opGraphicsElementShape->SetIsSelectable(false);
    opGraphicsElementShape->SetIsSnappable(false);
    opGraphicsElementShape->SetGraphicsStyleId(pDocument->GetGraphicsStyleManager()->GetGraphicsStyleIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_TEMP_STYLE));
    GraphicsNodeUtils::CleanGraphicsNodeStyleAndMaterial(pDocument, opGraphicsElementShape.get());

    opUserTransaction->Rollback();
    return TransferOwnership(opGraphicsElementShape);
}

gcmp::ElementId ActionDrawWall::OnDrawFinished(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& startPt, IN OUT gcmp::Vector3d& endPt)
{
    IDocument *pDocument = pCurrentView->GetUiDocument()->GetDbDocument();
    OwnerPtr<IUserTransaction> opUserTransaction =
        IUserTransaction::Create(pDocument, GBMP_TR(L"绘制墙体"));
    Wall* pWall = Wall::Create(pDocument, startPt, endPt, ElementCreationOptions::Normal);
    DBG_WARN_UNLESS(pWall, L"Wall不能为空", L"GDMP", L"2023-09-30");
    endPt = pWall->GetData()->GetEndPoint();
    opUserTransaction->Commit();
    return pWall->GetOwnerElement()->GetElementId();
}

bool ActionDrawWall::OnKeyDown(IUiView* pCurrentView, int nChar)
{
    if (nChar == VK_F8)
    {
        ICommandManager::Get()->SendCommand(ID_CMD_HELLOWORLD);
        return true;
    }
    return false;
}

bool ActionDrawWall::PreviewKeyEvent()
{
    return true;
}

bool ActionDrawWall::GetCtrlKeyPressed()
{
    return this->IsKeyAndButtonPressed(VK_CONTROL);
}

